package com.sharemarking.application.common;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.data.jpa.domain.Specification;

public class BaseSpecification<E extends BaseEntity> implements Specification<E> {
	
	private E e;
	
	public BaseSpecification(E e){
		this.e=e;
	}
	
	private <S,T> Predicate getPredicate(From<S,T> from,CriteriaBuilder cb,BaseEntity object){
		List<Predicate> list = new ArrayList<Predicate>();
		Field[] fields=object.getClass().getDeclaredFields();
		for(Field f:fields){
			Object o=null;
			if(Modifier.isPublic(f.getModifiers())||Modifier.isStatic(f.getModifiers()))continue;
			try {
				PropertyDescriptor pd = new PropertyDescriptor(f.getName(),object.getClass());
				Method getMethod=pd.getReadMethod();
				o=getMethod.invoke(object);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			if(o!=null){
				if(o instanceof String){
					if(!o.equals(""))list.add(cb.like(from.get(f.getName()).as(String.class),"%"+(String)o+"%"));
				}else if(o instanceof Integer){
					list.add(cb.equal(from.get(f.getName()).as(Integer.class),o));
				}else if(o instanceof Enum){
					list.add(cb.equal(from.get(f.getName()),o));
				}else if(o instanceof BaseEntity){
					list.add(getPredicate(from.join(f.getName()),cb,(BaseEntity)o));
				}
			}
		}
		if(object.getId()!=null)list.add(cb.equal(from.get("id").as(Integer.class),object.getId()));
		list.add(cb.equal(from.get("delFlag").as(Boolean.class), Boolean.FALSE));
		return cb.and(list.toArray(new Predicate[0]));
	}

	@Override
	public Predicate toPredicate(Root<E> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
		return getPredicate(root, cb, e);
	}

}
